using System;
using System.IO;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.Web.Services.Discovery;
using System.Web.Services.Description;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.JScript;
using Microsoft.VisualBasic;
using Microsoft.VisualC;
using Microsoft.CSharp;


namespace XWsdl {

    public class Program {
        /**************************************************************/
        /*                     Consts
        /**************************************************************/
        public const string DEFAULT_MESSAGE =
            "This program is used to create as Web Services proxy without the business\r\n" +
            "object generation. It's usefull when you want to share business object from\r\n" +
            "the server into the client. The server must be created in .Net. It's an extension\r\n" +
            "to the original wsdl.exe from Microsoft\r\n" +
            "\r\n" +
            "usage: xswdl.exe [options] /i:<url or path>\r\n" +
            "  options: \r\n" +
            "\r\n" +
            "/language:<filename> /l:<filename>\r\n" +
            "    Specified the output language {CS / VB / CPP/ JS}. CSharp is the default\r\n" +
            "\r\n" +
            "/enableDataBinding /edb\r\n" +
            "    Implement INotifyPropertyChanged interface on all generated types\r\n" +
            "    to enable data binding.\r\n" +
            "\r\n" +
            "/oldAsync /oa\r\n" +
            "    Generate the Old Async callback from version 1.X\r\n" +
            "\r\n" +
            "/namespace:<namespace> /n:<namespace>\r\n" +
            "    The namespace for the generated proxy or template.  The default namespace\r\n" +
            "    is the global namespace. If more than one specified, imports or using will be added\r\n" +
            "\r\n" +
            "/out:<fileName|directoryPath>\r\n" +
            "    The filename or directory path for the generated proxy code. The default\r\n" +
            "    filename is derived from the service name.";

        public const string SHORT_ENABLE_DATABINDING_SWITCH = "edb";
        public const string SHORT_INPUT_FILE_SWITCH = "i:";
        public const string SHORT_LANGUAGE_SWITCH = "l:";
        public const string SHORT_NAMESPACE_SWITCH = "n:";
        public const string SHORT_OLD_ASYNC = "oa";
        public const string SHORT_OUTPUT_FILE_SWITCH = "o:";

        public const string LONG_ENABLE_DATABINDING_SWITCH = "enableDataBinding";
        public const string LONG_INPUT_FILE_SWITCH = "input:";
        public const string LONG_LANGUAGE_SWITCH = "language:";
        public const string LONG_NAMESPACE_SWITCH = "namespace:";
        public const string LONG_OLD_ASYNC = "oldAsync";
        public const string LONG_OUTPUT_FILE_SWITCH = "out:";

        public const string LANGUAGE_CPP = "CPP";
        public const string LANGUAGE_CS = "CS";
        public const string LANGUAGE_JS = "JS";
        public const string LANGUAGE_VB = "VB";

        /**************************************************************/
        /*                     Public
        /**************************************************************/
          public static int Run() {
          
            string _InputFile;
            string _OutputFile;
            string _Language;
            string[] _NamespaceOptions;
            string _datasetNamespace;
            bool _useDefaultValueFordatasetNamespace;
            bool _EnableDataBindingOptions;
            bool _OldAsyncOptions;
            bool _excludeArrayList;

            frmParameters f = new frmParameters();
            if (f.ShowDialog() == DialogResult.OK)
            {
                _InputFile = f.InputOptions;
                _OutputFile = f.OutputOptions;
                _Language = f.LanguageOptions;
                _NamespaceOptions = f.NamespaceOptions;
                _datasetNamespace=f.DataSetNamespace;
                _useDefaultValueFordatasetNamespace = f.UseDefaultCriteraForDataSetNamespace;
                _EnableDataBindingOptions = f.EnableDataBindingOptions;
                _OldAsyncOptions = f.OldAsyncOptions;
                _excludeArrayList = f.ExcludeArrayList;
            }
            else
                return 0;

            f.Dispose();
            f=null;

            Uri _WsdlLocation;

            if (_InputFile.ToUpper().StartsWith("HTTP:")) {
                // TODO : tester url invalid
                _WsdlLocation = new Uri(_InputFile);
            } else {
                _InputFile = Path.GetFullPath(_InputFile);

                if (!File.Exists(_InputFile)) {
                    Console.WriteLine(String.Format("File \"{0}\" not found", _InputFile));
                    return -1;
                }

                _WsdlLocation = new Uri(_InputFile);            
            }

            Console.WriteLine("Beginning schema import.");
            Console.WriteLine();

            GenericSchemaImporterExtension.ImportNamespaces = _NamespaceOptions;
            GenericSchemaImporterExtension.DataSetNamespaces = _datasetNamespace;
            GenericSchemaImporterExtension.UseDefaultCriteraForDatasetNamespace=_useDefaultValueFordatasetNamespace;
            GenericSchemaImporterExtension.ExcludeArrayList = _excludeArrayList;

            DiscoveryClientProtocol _DiscoveryClientProtocol = new DiscoveryClientProtocol();
            _DiscoveryClientProtocol.AllowAutoRedirect = true;
            _DiscoveryClientProtocol.DiscoverAny(_WsdlLocation.ToString());
            _DiscoveryClientProtocol.ResolveAll();

            WebReferenceCollection _References = new WebReferenceCollection();

            //add 1st web reference document
            WebReference _WebReference = new WebReference(_DiscoveryClientProtocol.Documents, new CodeNamespace(GenericSchemaImporterExtension.ImportNamespaces[0]));
            _References.Add(_WebReference);

            CodeDomProvider _CodeProvider;

            if (_Language == LANGUAGE_CPP) {
                _CodeProvider = new CppCodeProvider();                
            } else if (_Language == LANGUAGE_VB) {
                _CodeProvider = new VBCodeProvider();
            } else if (_Language == LANGUAGE_JS) {
                _CodeProvider = new JScriptCodeProvider();                
            } else {
                _CodeProvider = new CSharpCodeProvider();
            }

            CodeCompileUnit _CodeCompileUnit = new CodeCompileUnit();
            _CodeCompileUnit.Namespaces.Add(_WebReference.ProxyCode);

             try {
                WebReferenceOptions _Option = new WebReferenceOptions();

                if (_OldAsyncOptions) {
                    _Option.CodeGenerationOptions |= CodeGenerationOptions.GenerateOldAsync;
                    _Option.CodeGenerationOptions &= ~CodeGenerationOptions.GenerateNewAsync;
                } else {
                    _Option.CodeGenerationOptions &= ~CodeGenerationOptions.GenerateOldAsync;
                    _Option.CodeGenerationOptions |= CodeGenerationOptions.GenerateNewAsync;
                }

                if (_EnableDataBindingOptions) {
                    _Option.CodeGenerationOptions |= CodeGenerationOptions.EnableDataBinding;                
                }
                
                    _Option.CodeGenerationOptions |= CodeGenerationOptions.GenerateOrder;


                ServiceDescriptionImporter.GenerateWebReferences(_References, _CodeProvider, _CodeCompileUnit, _Option);
            } catch (Exception ex) {
                Console.WriteLine("An exception occured during importation:\n {0}", ex);
                return -1;
            }

             foreach (string t in GenericSchemaImporterExtension.Types)
              {
                  Console.WriteLine(t);
              }

            using (StreamWriter _Writer = new StreamWriter(_OutputFile, false, new System.Text.UTF8Encoding(true))) {
                _CodeProvider.GenerateCodeFromCompileUnit(_CodeCompileUnit, _Writer, new CodeGeneratorOptions());
                Console.WriteLine();
                Console.WriteLine("Schema import completed.");
            }

            return 0;
        }

        [STAThread]
        public static int Main(string[] aArgs) {
            Console.WriteLine("wsdlEX - Extended Web Services Description Language Utility");
            bool exit=false;
            while (!exit){
                Run();

                Console.Write("Another proxy To Generate? [y/n] ");
                string risp=Console.ReadLine();
                if (risp.ToUpper() == "N")
                {
                    exit = true;
                }
            }
            return -1;

        }
    }
}
